﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;
using System.Globalization;
using System.Runtime.InteropServices;
using Tesla.Math;
using Tesla.Util;

namespace Tesla.Graphics {

    /// <summary>
    /// Represents a vertex that has position and texture coordinate data.
    /// </summary>
    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct VertexPositionTexture {
        /// <summary>
        /// Vertex Position
        /// </summary>
        public Vector3 Position;

        /// <summary>
        /// Vertex Texture Coordinate
        /// </summary>
        public Vector2 TextureCoordinate;

        /// <summary>
        /// Companion vertex declaration to use when dealing with this vertex type.
        /// </summary>
        public static readonly VertexDeclaration VertexDeclaration;

        /// <summary>
        /// Size of the structure in bytes.
        /// </summary>
        public static readonly int SizeInBytes;

        static VertexPositionTexture() {
            SizeInBytes = MemoryHelper.SizeOf<VertexPositionTexture>();
            VertexDeclaration = new VertexDeclaration(new VertexElement[] {
                new VertexElement(VertexSemantic.Position, 0, VertexFormat.Vector3, 0),
                new VertexElement(VertexSemantic.TextureCoordinate, 0, VertexFormat.Vector2, 12)
            });
        }

        /// <summary>
        /// Creates a new instance of <see cref="VertexPositionTexture"/>.
        /// </summary>
        /// <param name="position">The vertex position.</param>
        /// <param name="textureCoordinate">The vertex texture coordinate.</param>
        public VertexPositionTexture(Vector3 position, Vector2 textureCoordinate) {
            Position = position;
            TextureCoordinate = textureCoordinate;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj) {
            if(obj == null || !(obj is VertexPositionTexture)) {
                return false;
            }
            VertexPositionTexture test = (VertexPositionTexture) obj;
            return (test.Position == this.Position) && (test.TextureCoordinate == this.TextureCoordinate);
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(VertexPositionTexture a, VertexPositionTexture b) {
            return (a.Position == b.Position) && (a.TextureCoordinate == b.TextureCoordinate);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(VertexPositionTexture a, VertexPositionTexture b) {
            return (a.Position != b.Position) || (a.TextureCoordinate != b.TextureCoordinate);
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance.
        /// </returns>
        public override int GetHashCode() {
            int hash = Position.GetHashCode();
            hash = ((hash << 2) - hash) + TextureCoordinate.GetHashCode();
            return hash;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString() {
            return string.Format(CultureInfo.CurrentCulture, "{{Position:{0}, TextureCoordinate:{1}}}", new object[] { this.Position, this.TextureCoordinate });
        }
    }

    /// <summary>
    /// Represents a vertex with position and vertex color data.
    /// </summary>
    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct VertexPositionColor {
        /// <summary>
        /// Vertex Position
        /// </summary>
        public Vector3 Position;

        /// <summary>
        /// Vertex color.
        /// </summary>
        public Color VertexColor;

        /// <summary>
        /// Companion vertex declaration to use when dealing with this vertex type.
        /// </summary>
        public static readonly VertexDeclaration VertexDeclaration;

        /// <summary>
        /// Size of the structure in bytes.
        /// </summary>
        public static readonly int SizeInBytes;

        static VertexPositionColor() {
            SizeInBytes = MemoryHelper.SizeOf<VertexPositionColor>();
            VertexDeclaration = new VertexDeclaration(new VertexElement[] {
                new VertexElement(VertexSemantic.Position, 0, VertexFormat.Vector3, 0),
                new VertexElement(VertexSemantic.Color, 0, VertexFormat.Color, 12),
            });
        }

        /// <summary>
        /// Creates a new instance of <see cref="VertexPositionColor"/>.
        /// </summary>
        /// <param name="position">The vertex position.</param>
        /// <param name="vertexColor">The vertex color</param>
        public VertexPositionColor(Vector3 position, Color vertexColor) {
            Position = position;
            VertexColor = vertexColor;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj) {
            if(obj == null || !(obj is VertexPositionColor)) {
                return false;
            }
            VertexPositionColor test = (VertexPositionColor) obj;
            return (test.Position == this.Position) && (test.VertexColor == this.VertexColor);
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(VertexPositionColor a, VertexPositionColor b) {
            return (a.Position == b.Position) && (a.VertexColor == b.VertexColor);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(VertexPositionColor a, VertexPositionColor b) {
            return (a.Position != b.Position) || (a.VertexColor != b.VertexColor);
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance.
        /// </returns>
        public override int GetHashCode() {
            int hash = Position.GetHashCode();
            hash = ((hash << 2) - hash) + VertexColor.GetHashCode();
            return hash;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString() {
            return string.Format(CultureInfo.CurrentCulture, "{{Position:{0}, VertexColor:{1}}}", new object[] { this.Position, this.VertexColor});
        }
    }

    /// <summary>
    /// Represents a vertex with position, vertex color, and texture coordinate data.
    /// </summary>
    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct VertexPositionColorTexture {
        /// <summary>
        /// Vertex Position
        /// </summary>
        public Vector3 Position;

        /// <summary>
        /// Vertex color.
        /// </summary>
        public Color VertexColor;

        /// <summary>
        /// Vertex Texture Coordinate
        /// </summary>
        public Vector2 TextureCoordinate;

        /// <summary>
        /// Companion vertex declaration to use when dealing with this vertex type.
        /// </summary>
        public static readonly VertexDeclaration VertexDeclaration;

        /// <summary>
        /// Size of the structure in bytes.
        /// </summary>
        public static readonly int SizeInBytes;

        static VertexPositionColorTexture() {
            SizeInBytes = MemoryHelper.SizeOf<VertexPositionColorTexture>();
            VertexDeclaration = new VertexDeclaration(new VertexElement[] {
                new VertexElement(VertexSemantic.Position, 0, VertexFormat.Vector3, 0),
                new VertexElement(VertexSemantic.Color, 0, VertexFormat.Color, 12),
                new VertexElement(VertexSemantic.TextureCoordinate, 0, VertexFormat.Vector2, 16)
            });
        }

        /// <summary>
        /// Creates a new instance of <see cref="VertexPositionColorTexture"/>.
        /// </summary>
        /// <param name="position">The vertex position.</param>
        /// <param name="vertexColor">The vertex color</param>
        /// <param name="textureCoordinate">The vertex texture coordinate.</param>
        public VertexPositionColorTexture(Vector3 position, Color vertexColor, Vector2 textureCoordinate) {
            Position = position;
            VertexColor = vertexColor;
            TextureCoordinate = textureCoordinate;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj) {
            if(obj == null || !(obj is VertexPositionColorTexture)) {
                return false;
            }
            VertexPositionColorTexture test = (VertexPositionColorTexture) obj;
            return (test.Position == this.Position) && (test.VertexColor == this.VertexColor) && (test.TextureCoordinate == this.TextureCoordinate);
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(VertexPositionColorTexture a, VertexPositionColorTexture b) {
            return (a.Position == b.Position) && (a.VertexColor == b.VertexColor) && (a.TextureCoordinate == b.TextureCoordinate);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(VertexPositionColorTexture a, VertexPositionColorTexture b) {
            return (a.Position != b.Position) || (a.VertexColor != b.VertexColor) || (a.TextureCoordinate != b.TextureCoordinate);
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance.
        /// </returns>
        public override int GetHashCode() {
            int hash = Position.GetHashCode();
            hash = ((hash << 2) - hash) + VertexColor.GetHashCode();
            hash = ((hash << 2) - hash) + TextureCoordinate.GetHashCode();
            return hash;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString() {
            return string.Format(CultureInfo.CurrentCulture, "{{Position:{0}, VertexColor:{1}, TextureCoordinate:{2}}}", new object[] { this.Position, this.VertexColor, this.TextureCoordinate });
        }
    }

    /// <summary>
    /// Represents a vertex with position, normal, and texture coordinate data.
    /// </summary>
    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct VertexPositionNormalTexture {
         /// <summary>
        /// Vertex Position
        /// </summary>
        public Vector3 Position;

        /// <summary>
        /// Vertex Normal.
        /// </summary>
        public Vector3 Normal;

        /// <summary>
        /// Vertex Texture Coordinate
        /// </summary>
        public Vector2 TextureCoordinate;

        /// <summary>
        /// Companion vertex declaration to use when dealing with this vertex type.
        /// </summary>
        public static readonly VertexDeclaration VertexDeclaration;

        /// <summary>
        /// Size of the structure in bytes.
        /// </summary>
        public static readonly int SizeInBytes;

        static VertexPositionNormalTexture() {
            SizeInBytes = MemoryHelper.SizeOf<VertexPositionNormalTexture>();
            VertexDeclaration = new VertexDeclaration(new VertexElement[] {
                new VertexElement(VertexSemantic.Position, 0, VertexFormat.Vector3, 0),
                new VertexElement(VertexSemantic.Normal, 0, VertexFormat.Vector3, 12),
                new VertexElement(VertexSemantic.TextureCoordinate, 0, VertexFormat.Vector2, 24)
            });
        }

        /// <summary>
        /// Creates a new instance of <see cref="VertexPositionNormalTexture"/>.
        /// </summary>
        /// <param name="position">The vertex position.</param>
        /// <param name="normal">The vertex normal</param>
        /// <param name="textureCoordinate">The vertex texture coordinate.</param>
        public VertexPositionNormalTexture(Vector3 position, Vector3 normal, Vector2 textureCoordinate) {
            Position = position;
            Normal = normal;
            TextureCoordinate = textureCoordinate;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj) {
            if(obj == null || !(obj is VertexPositionNormalTexture)) {
                return false;
            }
            VertexPositionNormalTexture test = (VertexPositionNormalTexture) obj;
            return (test.Position == this.Position) && (test.Normal == this.Normal) && (test.TextureCoordinate == this.TextureCoordinate);
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(VertexPositionNormalTexture a, VertexPositionNormalTexture b) {
            return (a.Position == b.Position) && (a.Normal == b.Normal) && (a.TextureCoordinate == b.TextureCoordinate);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(VertexPositionNormalTexture a, VertexPositionNormalTexture b) {
            return (a.Position != b.Position) || (a.Normal == b.Normal) || (a.TextureCoordinate != b.TextureCoordinate);
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance.
        /// </returns>
        public override int GetHashCode() {
            int hash = Position.GetHashCode();
            hash = ((hash << 2) - hash) + Normal.GetHashCode();
            hash = ((hash << 2) - hash) + TextureCoordinate.GetHashCode();
            return hash;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString() {
            return string.Format(CultureInfo.CurrentCulture, "{{Position:{0}, Normal:{1}, TextureCoordinate:{2}}}", new object[] { this.Position, this.Normal, this.TextureCoordinate });
        }
    }

    /// <summary>
    /// Represents a vertex with position, normal, vertex color, and texture coordinate data.
    /// </summary>
    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct VertexPositionNormalColorTexture {
        /// <summary>
        /// Vertex Position
        /// </summary>
        public Vector3 Position;

        /// <summary>
        /// Vertex Normal.
        /// </summary>
        public Vector3 Normal;

        /// <summary>
        /// Vertex Color.
        /// </summary>
        public Color VertexColor;

        /// <summary>
        /// Vertex Texture Coordinate
        /// </summary>
        public Vector2 TextureCoordinate;

        /// <summary>
        /// Companion vertex declaration to use when dealing with this vertex type.
        /// </summary>
        public static readonly VertexDeclaration VertexDeclaration;

        /// <summary>
        /// Size of the structure in bytes.
        /// </summary>
        public static readonly int SizeInBytes;

        static VertexPositionNormalColorTexture() {
            SizeInBytes = MemoryHelper.SizeOf<VertexPositionNormalColorTexture>();
            VertexDeclaration = new VertexDeclaration(new VertexElement[] {
                new VertexElement(VertexSemantic.Position, 0, VertexFormat.Vector3, 0),
                new VertexElement(VertexSemantic.Normal, 0, VertexFormat.Vector3, 12),
                new VertexElement(VertexSemantic.Color, 0, VertexFormat.Color, 24),
                new VertexElement(VertexSemantic.TextureCoordinate, 0, VertexFormat.Vector2, 28)
            });
        }

        /// <summary>
        /// Creates a new instance of <see cref="VertexPositionNormalColorTexture"/>.
        /// </summary>
        /// <param name="position">The vertex position.</param>
        /// <param name="normal">The vertex normal</param>
        /// <param name="vertexColor">The vertex color</param>
        /// <param name="textureCoordinate">The vertex texture coordinate.</param>
        public VertexPositionNormalColorTexture(Vector3 position, Vector3 normal, Color vertexColor, Vector2 textureCoordinate) {
            Position = position;
            Normal = normal;
            VertexColor = vertexColor;
            TextureCoordinate = textureCoordinate;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj) {
            if(obj == null || !(obj is VertexPositionNormalColorTexture)) {
                return false;
            }
            VertexPositionNormalColorTexture test = (VertexPositionNormalColorTexture) obj;
            return (test.Position == this.Position) && (test.Normal == this.Normal) && (test.VertexColor == this.VertexColor) && (test.TextureCoordinate == this.TextureCoordinate);
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(VertexPositionNormalColorTexture a, VertexPositionNormalColorTexture b) {
            return (a.Position == b.Position) && (a.Normal == b.Normal) && (a.VertexColor == b.VertexColor) && (a.TextureCoordinate == b.TextureCoordinate);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="a">Left operand</param>
        /// <param name="b">Right operand</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(VertexPositionNormalColorTexture a, VertexPositionNormalColorTexture b) {
            return (a.Position != b.Position) || (a.Normal == b.Normal) || (a.VertexColor != b.VertexColor) || (a.TextureCoordinate != b.TextureCoordinate);
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance.
        /// </returns>
        public override int GetHashCode() {
            int hash = Position.GetHashCode();
            hash = ((hash << 2) - hash) + Normal.GetHashCode();
            hash = ((hash << 2) - hash) + VertexColor.GetHashCode();
            hash = ((hash << 2) - hash) + TextureCoordinate.GetHashCode();
            return hash;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString() {
            return string.Format(CultureInfo.CurrentCulture, "{{Position:{0}, Normal:{1}, VertexColor:{2}, TextureCoordinate:{3}}}", new object[] { this.Position, this.Normal, this.VertexColor, this.TextureCoordinate });
        }
    }
}
